#include "tcp.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/sendfile.h>

namespace wilson::net
{
    tcp_conn::tcp_conn(sys::fd_guard fd)
        : tc_fd{ ::std::move(fd) }
    {
    }

    void tcp_conn::close()
    {
        tc_fd.close();
    }

    void tcp_conn::shutdown()
    {
        if (!tc_fd.empty())
            ::shutdown(tc_fd, SHUT_RDWR);
    }

    void tcp_conn::shutdown_read()
    {
        if (!tc_fd.empty())
            ::shutdown(tc_fd, SHUT_RD);
    }

    void tcp_conn::shutdown_write()
    {
        if (!tc_fd.empty())
            ::shutdown(tc_fd, SHUT_WR);
    }

    ssize_t tcp_io::recv(
        ::std::span<::std::byte> buffer, int flags)
    {
        // return 0 if the peer has shut the channel down.(EPOLLHUP)
        return ::recv(
            fd(), buffer.data(), buffer.size(), flags | MSG_NOSIGNAL
        );
    }

    ssize_t tcp_io::recvmsg(::msghdr* hdr, int flags)
    {
        // return 0 if the peer has shut the channel down.(EPOLLHUP)
        return ::recvmsg(
            fd(), hdr, flags | MSG_NOSIGNAL
        );
    }

    ssize_t tcp_io::read(::std::span<::std::byte> buffer)
    {
        // return 0 if the peer has shut the channel down.(EPOLLHUP)
        return ::read(
            fd(), 
            reinterpret_cast<void*>(buffer.data()), 
            buffer.size()
        );
    }

    ssize_t tcp_io::send(sys::borrowed_fd file_fd, size_t count, int flags)
    {
        return ::sendfile(fd(), file_fd, nullptr, count);
    }

    ssize_t tcp_io::send(::std::string_view str, int flags)
    {
        return tcp_io::send(
            ::std::span{ 
                reinterpret_cast<const ::std::byte*>(str.data()), 
                str.size() 
            }, 
            flags | MSG_NOSIGNAL
        );
    }

    ssize_t tcp_io::send(::std::span<const ::std::byte> buffer, int flags)
    {
        // ERROR 
        return ::send(
            fd(), 
            reinterpret_cast<const void*>(buffer.data()), 
            buffer.size(), 
            flags | MSG_NOSIGNAL
        );
    }

    ssize_t tcp_io::sendmsg(const ::msghdr* hdr, int flags)
    {
        return ::sendmsg(fd(), hdr, flags | MSG_NOSIGNAL);
    }

    ssize_t tcp_io::write(::std::span<const ::std::byte> buffer)
    {
        return ::write(
            fd(), 
            reinterpret_cast<const void*>(buffer.data()), 
            buffer.size()
        );
    }
}
